А еще у меня там местами xpcall отладочный висит, там где я ловил косяки и не убрал его потом, без него код чуть проще становится, он нужен только для отлова ошибок и в моем случае вывода их на экран.
Это печально, новые костыли, а я уже обрадовался, что ничего обнулять и чистить не нужно =(
Не нужно обнулять локалки в функциях и все что ограниченного срока жизни, но всякие системы хранения данных они же либо глобальные либо в "локальном" скопе всей карты и, соответственно, живут пока загружена карта - там вручную подчищать надо, естественно. Можно делать это полу-автоматически как у меня, можно вручную когда становится известно что данные уже не нужны. Можно было бы использовать таблицу со слабыми ключами, но тогда возникает вопрос что использовать в качестве ключей - можно прямо на самого юнита вешать, чтобы когда игра его удалит из памяти, таблица почистилась сборщиком мусора, но нет гарантии что это будет работать и не будет вызывать десинки т.к. сборщику мусора синхронизация не указ. Bergi_Bear:
но мне можно себе такой вариант забрать или надо ещё что-то дополнительно записать?
У меня библиотека отгорожена только ради того чтобы автоматизировать сборку мусора и создание новых таблиц при обращении по хендлу на который ничего нет.
Минимальный вариант, наверно, такой:
local HandleData = {} -- я использую локальные переменные в скопе карты, при этом важен порядок но доступ к ним идет чуть быстрее чем в глобальном скопе
function ForceUnit (u,a,d,s,flag)
local data = HandleData[GetHandleId(u)]
if (data==nil) then data = {} HandleData[GetHandleId(u)] = data end
data.a = a
data.d = d
data.s = s
data.flag = flag
GroupAddUnit(gforce, u)
end
-- --------------
ForGroup(gforce, function()
local u=GetEnumUnit()
local h=GetHandleId(u)
local data = HandleData[h]
local a=data.a
local d=data.d
local s=data.s
local flag=data.flag
...
end
Я бы поработал с блокираторами пути. Сделать особый блокиратор (только для индикации), который как бы говорит нам о том, что можно идти и под ним, и по нему, а дальше физика в зависимости от текущего положения.
С регионами просто больше времени потратишь
Головокружение - дамми каст в цель какого нить увечья или замедления волшебницы, а урон наносится функцией UnitDamageTarget в разделе Unit на гуях. Подробно - смотри конфетные войны 2004 от близзардов, там это есть.
По названиям функций думаю понятно что они делают, рассмотрим по подробнее MeleeInitVictoryDefea( )
function MeleeInitVictoryDefeat takes nothing returns nothing
local trigger trig
local integer index
local player indexPlayer
// Create a timer window for the "finish soon" timeout period, it has no timer
// because it is driven by real time (outside of the game state to avoid desyncs)
set bj_finishSoonTimerDialog = CreateTimerDialog(null)
// Set a trigger to fire when we receive a "finish soon" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_SOON)
call TriggerAddAction(trig, function MeleeTriggerTournamentFinishSoon)
// Set a trigger to fire when we receive a "finish now" game event
set trig = CreateTrigger()
call TriggerRegisterGameEvent(trig, EVENT_GAME_TOURNAMENT_FINISH_NOW)
call TriggerAddAction(trig, function MeleeTriggerTournamentFinishNow)
// Set up each player's mortality code.
set index = 0
loop
set indexPlayer = Player(index)
// Make sure this player slot is playing.
if (GetPlayerSlotState(indexPlayer) == PLAYER_SLOT_STATE_PLAYING) then
set bj_meleeDefeated[index] = false
set bj_meleeVictoried[index] = false
// Create a timer and timer window in case the player is crippled.
set bj_playerIsCrippled[index] = false
set bj_playerIsExposed[index] = false
set bj_crippledTimer[index] = CreateTimer()
set bj_crippledTimerWindows[index] = CreateTimerDialog(bj_crippledTimer[index])
call TimerDialogSetTitle(bj_crippledTimerWindows[index], MeleeGetCrippledTimerMessage(indexPlayer))
// Set a trigger to fire whenever a building is cancelled for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_CANCEL, null)
call TriggerAddAction(trig, function MeleeTriggerActionConstructCancel)
// Set a trigger to fire whenever a unit dies for this player.
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddAction(trig, function MeleeTriggerActionUnitDeath)
// Set a trigger to fire whenever a unit begins construction for this player
set trig = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(trig, indexPlayer, EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
call TriggerAddAction(trig, function MeleeTriggerActionUnitConstructionStart)
// Set a trigger to fire whenever this player defeats-out
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_DEFEAT)
call TriggerAddAction(trig, function MeleeTriggerActionPlayerDefeated)
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
// Set a trigger to fire whenever this player changes his/her alliances.
set trig = CreateTrigger()
call TriggerRegisterPlayerAllianceChange(trig, indexPlayer, ALLIANCE_PASSIVE)
call TriggerRegisterPlayerStateEvent(trig, indexPlayer, PLAYER_STATE_ALLIED_VICTORY, EQUAL, 1)
call TriggerAddAction(trig, function MeleeTriggerActionAllianceChange)
else
set bj_meleeDefeated[index] = true
set bj_meleeVictoried[index] = false
// Handle leave events for observers
if (IsPlayerObserver(indexPlayer)) then
// Set a trigger to fire whenever this player leaves
set trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, indexPlayer, EVENT_PLAYER_LEAVE)
call TriggerAddAction(trig, function MeleeTriggerActionPlayerLeft)
endif
endif
set index = index + 1
exitwhen index == bj_MAX_PLAYERS
endloop
// Test for victory / defeat at startup, in case the user has already won / lost.
// Allow for a short time to pass first, so that the map can finish loading.
call TimerStart(CreateTimer(), 2.0, false, function MeleeTriggerActionAllianceChange)
endfunction
Вроде много, но тут все просто, создается три триггера один следит за тем сколько построил зданий любой играющий игрок, второй следит сколько зданий погибло у любого играющего игрока, ну а третий следит за теми кто ливнул, чтобы их не преребирать, два прочих вспомогательные, следят за отмненой строительства и прочее.
Итого делаем вывод, чтобы узнать проиграл или нет игрок, нам нужно узнать сколько у него живых зданий, меньше 1 игрок проиграл. А реализовать это можно как угодно, триггерами следящими за смертями и прочим или таймером, который будет переодически считать все здания каждого игрока и давать поражение тем игрокам у кого не осталось ни одного здания...
RobertStevenson, вейты вообще зло, а отсчёт можно сделать таймером. Точнее и без неожиданных багов.
Ждать пока - это вейт в цикле, работает это просто отвратно, сам с этим сталкивался. Лучше заменить на событие смерти колдуна.
Я всё же думаю, что дело не в вейтах. Выводи имя героя Hero[A]. Лучше выводить так: ("герой - ") + (Имя юнита (Hero[A])) + " " + (Число в строку (А)).
Если нет имени - героя просто нет в этой переменной.
TheBlakeRed, сорь что не ответил сразу, в бане сидел, в общем у тебя вместо включения триггера на вход - его выключение, а портал у тебя не тот стоял в условиях, равкоды смотреть надо, у людей во вкладке кампания такой портал, а у тебя нейтралы - сражения - ашенвальский портал, который как здание выглядит
в общем я поправил и добавил ещё один вариант со стандартным порталом, тебе нужно просто разблокировать одни функции на портал и заблокировать/удалить другие, думаю ты разберёшься
reaper1691, так в чем проблема? Морф, две формы героя, один конь, одна способность-пустышка отвечающая за выбор коня и запуск триггера, который коня скроет, а герою запустит морф через предмет-руну, еще одна способность-пустышка, которая отвечает за запуск триггера запускающего обратный морф, телепортацию коня к герою и отмену скрытия коня.
Варик подключает разные функции ИИ к разным игрокам, например, юниты компьютерного игрока не будут бежать в другой конец карты, а вернутся на свою позицию через какое-то расстояние или время. Теперь известно, что и за ретаргет при стане тоже ИИ отвечает.
идея неплохая, если не считать, что заклинание будет диспеллить эффект похожего заклинания.
Например если юнит в стане от молота бурь, то молот бурь-даммикаст снимет бафф с него. С кислотной бомбой и т.п. однозначно диспеллит, насчёт молота - скорее всего.
Нет, станы перебивают тока сильный, слабого. Ну или есть большое отличие в уровнях. Аксид бомбы будут перебивать если урон выше, а так просто продливать бафф, чертики тоже самое.
Кстати да, забыл написать, длительность 0.01, бафф сразу же после проверки удаляем.
Если вы юзайте аксид бомбу для нанесения урона, придется наносит урон триггерно.
Кстати, большинство скиллов вроде аксид бомбы или чертика работают так.
Сначала 0.00 ед. урона, после бафф, после урон указанный в поле способности.
Но молот бурь работает иначе, сначала урон указанный в поле способности, после 0.00 ед. урона и бафф стана.
Чем сложнее модель снаряда - тем больше нагрузки в сумме
Например 100 обыкновенных кирпичей не будут сильно нагружать
А вот к примеру 100 болтов с "электрическим" эффектом ещё и с анимацией, ещё как будут нагружать
то скорость разная, то вылетают не из героя а из какой то псевдо центральной точки
в общем я полностью добился желаемого результата, никакого прерывания, ни каких лагов и странных поведений (то что снаряды врезаются в трупы так и задумано =))
вот мой код
//! beginusercode
--какие то общие функции
function MoveX (x, Dist, Angle)
return x+Dist*Cos(Angle*0.0175)
end
function MoveY (x, Dist, Angle)
return x+Dist*Sin(Angle*0.0175)
end
function AbilityId(id)
return id:byte(1) * 0x1000000 + id:byte(2) * 0x10000 + id:byte(3) * 0x100 + id:byte(4)
end
function Out(x,y)
return ( ( GetRectMinX(bj_mapInitialPlayableArea) <= x ) and ( x <= GetRectMaxX(bj_mapInitialPlayableArea) ) and ( GetRectMinY(bj_mapInitialPlayableArea) <= y ) and ( y <= GetRectMaxY(bj_mapInitialPlayableArea) ) ) or IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) == false
end
GetTerrainZ_location = Location(0, 0)
function GetTerrainZ(x,y)
MoveLocation(GetTerrainZ_location, x, y);
return GetLocationZ(GetTerrainZ_location);
end
function ehandler( err )
print( "ERROR:", err )
end
--/////// глобалки (хотя какая разница где объявить то)
perebor=CreateGroup()
--/////// триггер
local trigger = CreateTrigger()
for i = 0, bj_MAX_PLAYER_SLOTS - 1, 1 do
TriggerRegisterPlayerUnitEvent(trigger, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT)
end
TriggerAddCondition(trigger, Condition(function() return
GetOwningPlayer(GetTriggerUnit()) == Player(0)
end))
local d=0
TriggerAddAction(trigger, function()
local u=GetTriggerUnit()
local z=GetTerrainZ(GetUnitX(u),GetUnitY(u))
print("perodstart")
TimerStart(CreateTimer(), 0.1, true, function()
d=d+1
--print("abiclick "..d)
-- будущая фукция запуска снаряда
local x=GetUnitX(u)
local y=GetUnitY(u)
local eff=AddSpecialEffect("Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl", x, y)
local d2=1000
local a=GetUnitFacing(u)
TimerStart(CreateTimer(), 0.032, true, function()
d2=d2-10
x=MoveX(x,25,a)
y=MoveY(y,25,a)
BlzSetSpecialEffectPosition(eff, x, y, GetTerrainZ(x,y)+30)
-- урон
local e=nil
GroupEnumUnitsInRange(perebor,x,y,80,null)
while true do
e = FirstOfGroup(perebor)
if e == nil then break end
if IsUnitEnemy(e, GetOwningPlayer(u)) then
UnitDamageTarget( u, e, BlzGetUnitBaseDamage(u, 1), false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS )
-- print("наносим урон")
DestroyEffect(eff)
eff=nill
end
GroupRemoveUnit(perebor,e)
end
--print(d2)
if d2<=0 or Out(x,y)==false or eff==nil then
-- print("УМРИ!")
DestroyEffect(eff)
DestroyTimer(GetExpiredTimer())
end
end)
end)
end)
//! endusercode
а вот и карта
Выражаю огромную благодарность NazarPunk, и Prog за оказанную помощь и наставления
Выводы:
Более навороченные (в техническом плане) способы не всегда самые оптимальные
Точно также можно двигать эффекты и на мемхаке, так что 126 пат так же может удостоится высокой производительностью для огромного количества снарядов
Мой комп держит на 1 экране около 700 объектов в режиме 60+ FPS (с отключенной вертикальной синхронизацией, это когда макс фпс за 200)
EviLInside, в структуре находится таймер и группа, таймер запускаешь на функцию удаления, а всем юнитам в группе в этой структуре сохраняешь саму структуру, чтобы доставать и наносить разовый урон если кто-то из них его получит от постороннего источника, в таймер тоже сохраняешь, по окончании действия таймера выбираешь всех юнитов в группе и очищаешь им сохранённую структуру, т.к. сама структура лишь 1 раз создалась на этот спелл, то и уничтожить её вместе с группой и таймером достаточно 1 раз, в истекающем таймере
короче один раз создал и посохранял её везде, потом уничтожил в истекающем таймере и очистил везде где сохранял
» WarCraft 3 / Условие на движение
» WarCraft 3 / Warcraft III World Edit компания
» WarCraft 3 / Reforged - Доп.Кампании
» IrInA Host Bot / заявка на верификацию
» WarCraft 3 / Вопрос по лору
» IrInA Host Bot / Заявка на верификацию
» WarCraft 3 / Не работает триггер победы
» IrInA Host Bot / Заявка на верификацию
» IrInA Host Bot / Заявка на верификацию
» WarCraft 3 / Не работает спелл у предмета
» IrInA Host Bot / Верификация
» WarCraft 3 / АИ приоритеты цели
» IrInA Host Bot / Заявка на верификацию
» WarCraft 3 / Восход города полей
» WarCraft 3 / High Elven Japanese Citizens Assets Icon
» WarCraft 3 / Japanese United Nations Costumes NPCs
» WarCraft 3 / Night Elven Japanese Citizens
» Администрация XGM / Рекомендации
» WarCraft 3 / Снаряды заклинаний
» WarCraft 3 / Орк скверны